/*
 * BasicTsMediaCaster.cpp
 *
 *  Created on: 2019年2月28日
 *      Author: terry
 */

#include "BasicTsMediaCaster.h"
#include "CLog.h"
#include "FfmpegTsMuxer.h"
#include "TSafeStr.h"


namespace av
{

BasicTsMediaCaster::BasicTsMediaCaster():
        m_id(),
        m_videoLastPts(),
        m_audioLastPts()
{
    m_muxer.reset(new FfmpegTsMuxer());
    m_muxer->setSink(this);
}

BasicTsMediaCaster::~BasicTsMediaCaster()
{
}

void BasicTsMediaCaster::setID(int id)
{
    comn::AutoCritSec lock(m_cs);
    m_id = id;
}

int BasicTsMediaCaster::getID()
{
    return m_id;
}

bool BasicTsMediaCaster::addTarget(const std::string& ip, uint16_t port)
{
    CLog::debug("(%d) addTarget. ip:%s port:%d\n", m_id, ip.c_str(), port);

    NetAddress addr(ip, port);

    bool done = false;
    comn::AutoCritSec lock(m_cs);
    NetAddressArray::iterator it = std::find(m_targets.begin(), m_targets.end(), addr);
    if (it == m_targets.end())
    {
        m_targets.push_back(addr);

        done = true;
    }

    return done;
}

void BasicTsMediaCaster::removeTarget(const std::string& ip, uint16_t port)
{
    CLog::debug("(%d) removeTarget. ip:%s port:%d\n", m_id, ip.c_str(), port);

    NetAddress addr(ip, port);

    comn::AutoCritSec lock(m_cs);

    NetAddressArray::iterator it = std::remove(m_targets.begin(), m_targets.end(), addr);
    if (it != m_targets.end())
    {
        m_targets.erase(it);
    }
}

size_t BasicTsMediaCaster::getTargetCount()
{
    comn::AutoCritSec lock(m_cs);
    return m_targets.size();
}

void BasicTsMediaCaster::removeAllTarget()
{
    comn::AutoCritSec lock(m_cs);
    m_targets.clear();
}

bool BasicTsMediaCaster::write(int type, uint8_t* data, int size, int64_t pts, int duration, int flags)
{
    comn::AutoCritSec lock(m_cs);

    if (type == MEDIA_TYPE_VIDEO)
    {
        if (m_videoLastPts > 0)
        {
            if (m_videoLastPts > pts)
            {
                CLog::warning("(%d) video pts is invalid. last:%lld, now:%lld\n", m_id, m_videoLastPts, pts);
            }
        }

        bool isKeyFrame = false;
        int naluType = 0;
        m_propDetector.detect(data, size, isKeyFrame, naluType);

        flags |= isKeyFrame ? MEDIA_FLAG_KEY : 0;

        MPacket inPkt;
        inPkt.type = MEDIA_TYPE_VIDEO;
        inPkt.data = data;
        inPkt.size = size;
        inPkt.pts = pts;
        inPkt.flags = flags;
        inPkt.duration = 0;

        MPacket outPkt;
        memset(&outPkt, 0, sizeof(outPkt));

        if (m_naluJoiner->write(inPkt, naluType, outPkt))
        {
            m_muxer->write(outPkt.type, outPkt.data, outPkt.size,
                outPkt.pts, outPkt.duration, outPkt.flags);
        }
        else
        {
            // pass
        }

        m_videoLastPts = pts;

        //CLog::debug("write video. size:%d. pts:%lld, duration:%d.    elapse:%d\n",
        //              size, pts, duration, (int)elapse);

        return true;
    }
    else
    {
        if (m_audioLastPts > 0)
        {
            if (m_audioLastPts > pts)
            {
                CLog::warning("(%d) autio pts is invalid. last:%lld, now:%lld\n", m_id, m_audioLastPts, pts);
            }
        }

        m_audioLastPts = pts;
        return m_muxer->write(type, data, size, pts, duration, flags);
    }
}

bool BasicTsMediaCaster::openMuxer(const MediaFormat& fmt)
{
    int ret = m_muxer->open(fmt);

    m_format = fmt;

    m_propDetector.setCodec(fmt.m_codec);
    m_naluJoiner.reset(createNaluJoiner(fmt.m_codec));

    return ret == 0;
}

void BasicTsMediaCaster::closeMuxer()
{
    if (m_muxer->isOpen())
    {
        m_muxer->close();
    }
}

void BasicTsMediaCaster::setName(const char* name)
{
    if (name)
    {
        m_name = name;
    }
    else
    {
        m_name.clear();
    }
}


void BasicTsMediaCaster::fireEvent(int type)
{
    CasterEvent event;
    event.type = type;
    event.handle = m_id;
    comn::copyStr(event.name, m_name);
    fireEvent(event);
}

void BasicTsMediaCaster::fireEvent(CasterEvent& event)
{
    // pass
}


} /* namespace av */
